// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// f [author] rhyme_lph
// A [email]  rhymelph@gmail.com
// J [github] https://github.com/rhymelph

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/contribution_entity.dart';
import 'package:finance_app/src/entities/custom_expense_data.dart';
import 'package:finance_app/src/entities/employee_contact_entity.dart';
import 'package:finance_app/src/http_service/http_payslips_service.dart';
import 'package:finance_app/src/mixin/init_edit_data_mixin.dart';
import 'package:finance_app/src/page/dashboard/amount_gst/amount_gst_rate_category_page.dart';
import 'package:finance_app/src/page/dashboard/expense/new_expense_page.dart';
import 'package:finance_app/src/page/hr_payroll/payroll/payroll_detail_page.dart';
import 'package:finance_app/src/provider/dashboard_provider.dart';
import 'package:finance_app/src/provider/hr_payroll/hr_and_payroll_provider.dart';
import 'package:finance_app/src/provider/hr_payroll/views/payroll_provider.dart';
import 'package:finance_app/src/router_gen/override_route_providers.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/date_time_utils.dart';
import 'package:finance_app/src/utils/permission_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/add_fixed_deduction_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/add_income_type_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/basic_income_type_update_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/shg_contribution_bottom_sheet.dart';
import 'package:flutter/material.dart';

class PayrollDetailProvider extends BaseProvider<PayslipsItemEntity>
    with InitEditDataMixin<PayslipsItemEntity> {
  List<String> menuList = [
    // 'Edit',
    'Delete',
    'Record Payment',
  ];

  List<EmployeeContactDeductionData> deductionData;

  ContributionEntity contribution;
  String contributionAmount;

  String statusType;

  DateTime paidAt;

  String paymentTypeName;

  @override
  Future get dataFuture => HttpPayslipsService.payslipsDetails(id);

  List<EmployeeContactIncomeData> incomeData;

  @override
  void initState() {
    // if (!Config.hasPermission(PermissionUtils.hrPayroll)) {
    //   menuList = [];
    // }
    super.initState();
  }

  void onSave() async {
    PayslipsItemEntity entity;
    List _incomeDate = incomeData
        .map((e) => {
              "name": e.name,
              "amount": e.amount,
              "cpf_payable": e.cpfPayable,
              "wage_type": e.wageType,
              "currency_code": e.currencyCode
            })
        .toList();

    List _deductionData = deductionData
        .map((e) => {
              "name": e.name,
              "amount": e.amount,
              "currency_code": e.currencyCode
            })
        .toList();
    await post(
        HttpPayslipsService.updatePayslip(
          id,
          contribution: contribution?.key,
          contribution_amount:
              double.parse(contributionAmount ?? '', (e) => null),
          income_data: _incomeDate,
          deduction_data: _deductionData,
        ),
        autoHandler: AutoHandler.Toast,
        loadingTip: S.current.loading, onSuccess: (result) {
      entity = getEntityFromResult<PayslipsItemEntity>(result);
    });
    if (entity != null) {
      initData(entity);
      Providers.get<HrAndPayrollProvider>(
              RouterGenProviders.hrAndPayrollPage, null)
          ?.getChildProvider<PayrollProvider>()
          ?.updatePayslipItem(entity);
      if (!Config.hasPermission(PermissionUtils.homeDashboard))
        Config.dashboardProvider
            ?.getChildProvider<HrAndPayrollProvider>()
            ?.getChildProvider<PayrollProvider>()
            ?.updatePayslipItem(entity);
      update();
    }
  }

  void onSelectMenu(String value) {
    switch (value) {
      case 'Edit':
        onChangeEditMode();
        break;
      case 'Delete':
        _onDelete();
        break;
      case 'Record Payment':
        onRecordPayment();
        break;
      case 'See Payment':
        onSeePayment();
        break;
    }
  }

  void onAddIncomeType() {
    obtainContext?.call((context) async {
      final result = await Routes.navigateTo(
          RouterGenProviders.selectIncomeTypePage,
          params: {
            'currency': incomeData.first.currencyCode,
          });
      if (result != null) {
        incomeData.add(EmployeeContactIncomeData()
          ..name = result['title']
          ..amount = num.parse(result['controller'].text)
          ..currencyCode = incomeData.first.currencyCode);
        update();
      }
    });
  }

  void onIncomeTypeDetail(EmployeeContactIncomeData e, bool isFirst) {
    if (isFirst == true) {
      obtainContext?.call((context) async {
        final result = await showBasicIncomeTypeUpdateBottomSheet(
            context, e.amount?.toString());
        if (result != null && result is Map) {
          e
            ..amount = num.parse(result['amount'])
            ..currencyCode = incomeData.first.currencyCode;
        }
        update();
      });
    } else {
      obtainContext?.call((context) async {
        final result = await showAddIncomeTypeBottomSheet(
            context, e.amount?.toString(), e.name, e.wageType, 0, false);
        if (result != null && result is Map) {
          e
            ..name = result['incomeType']
            ..amount = num.parse(result['amount'])
            ..currencyCode = incomeData.first.currencyCode;
        } else if (result != null && result is bool) {
          incomeData.remove(e);
        }
        update();
      });
    }
  }

  void onAddFixedDeduction() {
    obtainContext?.call((context) async {
      final result = await showAddDeductionTypeBottomSheet(context, null, null);
      if (result != null) {
        deductionData.add(EmployeeContactDeductionData()
          ..name = result['deductionType']
          ..amount = num.parse(result['amount'])
          ..currencyCode = incomeData.first.currencyCode);
        update();
      }
    });
  }

  void onSelectFixedDeduction(EmployeeContactDeductionData e) {
    obtainContext?.call((context) async {
      final result = await showAddDeductionTypeBottomSheet(
          context, e.amount?.toString(), e.name);
      if (result != null && result is Map) {
        e.name = result['deductionType'];
        e.amount = num.parse(result['amount']?.toString());
      } else if (result != null && result is bool) {
        deductionData.remove(e);
      }
      update();
    });
  }

  PayslipsItemEntity payslips;

  void initData(PayslipsItemEntity data) {
    if (data == null) return;
    init(data.id);
    payslips = data;
    incomeData = data.incomeData;
    deductionData = data.deductionData;
    contributionAmount = data.contributionAmount;
    contribution = Config.settingData.contribution.firstWhere(
        (element) => element.key == data.contribution,
        orElse: () => null);
    statusType = data.status;
    paymentTypeName = data.paymentTypeName;
    paidAt = DateTimeUtils.toDateTime(data.paidAt);
    if (Config.isStaff) {
      menuList = [];
    } else if (statusType == 'closed') {
      menuList = ['See Payment'];
    }
  }

  void onRecordPayment() async {
    CustomExpenseData customData = CustomExpenseData(
        ids: [id],
        orderType: 'payslip',
        paidTo: payslips.name,
        date: payslips.endDate,
        totalAmount: payslips.reimbursement + payslips.nettAmount);
    Map<String, dynamic> data =
        await Routes.navigateTo(RouterGenProviders.newCashOutPage, params: {
      'customExpenseData': customData,
      'payslipNumber': payslips?.number,
      'currency': SettingDataCurrency()..key = incomeData.first.currencyCode,
    });
    if (data != null) {
      await post(HttpPayslipsService.payslipsDetails(id),
          autoHandler: AutoHandler.Toast,
          loadingTip: S.current.loading, onSuccess: (result) {
        transformData(getEntityFromResult<PayslipsItemEntity>(result), false);
      });
      statusType = 'closed';
      menuList = ['See Payment'];

      paidAt = DateTime.parse(data['payment_date']);
      paymentTypeName = data['payment_method'];
      Providers.get<HrAndPayrollProvider>(
              RouterGenProviders.hrAndPayrollPage, null)
          ?.getChildProvider<PayrollProvider>()
          ?.updatePayslipStatus(id, statusType, paidAt, paymentTypeName);
      if (!Config.hasPermission(PermissionUtils.homeDashboard))
        Config.dashboardProvider
            ?.getChildProvider<HrAndPayrollProvider>()
            ?.getChildProvider<PayrollProvider>()
            ?.updatePayslipStatus(id, statusType, paidAt, paymentTypeName);
      update();
    }
  }

  void onSeePayment() async {
    Map<String, dynamic> data =
        await Routes.navigateTo(RouterGenProviders.newCashOutPage, params: {
      'data': TransactionEntity()
        ..transactionableId = payslips?.payments?.first?.id,
      'isSelectMode': true
    });
    loadData();
  }

  void _onDelete() async {
    obtainContext?.call((context) async {
      final result = await showDeletePayslipsBottomSheet(context);
      if (result == true) {
        bool isSuccess = false;
        await post(HttpPayslipsService.payslipsDelete(id),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess) {
          await showPayslipsDeleteSuccessBottomSheet(context);
          Navigator.of(context).pop({
            'delete': true,
          });
        }
      }
    });
  }

  void onSelectContribution() {
    obtainContext?.call((context) async {
      final result = await showSHGContributionBottomSheet(context,
          amount: double.parse(contributionAmount ?? '', (e) => null),
          contribution: contribution);
      if (result != null) {
        contributionAmount = result['amount'].toString();
        contribution = (result['contribution'] as ContributionEntity);
        update();
      }
    });
  }

  @override
  Future get editDataFuture => dataFuture;

  @override
  TextEditingController get numberCtl => null;

  @override
  String get type => null;

  @override
  FutureOr<PayslipsItemEntity> transformData(
      PayslipsItemEntity d, bool isCache) {
    payslips = d;
    incomeData = d.incomeData;
    deductionData = d.deductionData;
    contributionAmount = d.contributionAmount;
    contribution = Config.settingData.contribution.firstWhere(
        (element) => element.key == d.contribution,
        orElse: () => null);
    statusType = data.status;
    if (statusType == 'open') {
      if (Config.isStaff) {
        menuList = [];
      } else {
        menuList = [
          'Delete',
          'Record Payment',
        ];
      }
    } else {
      menuList = ['See Payment'];
    }
    paymentTypeName = data.paymentTypeName;
    paidAt = DateTimeUtils.toDateTime(data.paidAt);

    Providers.get<HrAndPayrollProvider>(
            RouterGenProviders.hrAndPayrollPage, null)
        ?.getChildProvider<PayrollProvider>()
        ?.updatePayslipStatus(id, statusType, paidAt, paymentTypeName);
    if (!Config.hasPermission(PermissionUtils.homeDashboard))
      Config.dashboardProvider
          ?.getChildProvider<HrAndPayrollProvider>()
          ?.getChildProvider<PayrollProvider>()
          ?.updatePayslipStatus(id, statusType, paidAt, paymentTypeName);
    return super.transformData(d, isCache);
  }
}
